#include <assert.h>

#include "signal.hpp"

Signal::signal_t Signal::_signals[] = 
{
	{SIG_RELOAD,   "SIG_RELOAD",   "reload",  handler},
	{SIG_STOP,     "SIG_STOP",     "stop",    handler},

	{SIGPIPE,  "SIGPIPE",  "",        SIG_IGN},
	{SIGCHLD,  "SIGCHLD",  "",        SIG_IGN},
	{0,        NULL,       NULL,      NULL}
};

int Signal::_op = Signal::OP_NOTHING;

Signal::Signal()
{
	_pid       = 0;

	_pid_file  = "./log.pid";

	_init      = false;
}

Signal::~Signal()
{
}

int Signal::init(const std::string & pid_file)
{
	if (_init)
	{
		return 0;
	}

	if (!pid_file.empty())
	{
		_pid_file = pid_file;
	}

	Signal::signal_t * sig;
	struct sigaction   sa;

	for (sig = _signals; sig->signo != 0; ++ sig)
	{
		memset(&sa, 0, sizeof(struct sigaction));
		sa.sa_handler = sig->handler;
		sigemptyset(&sa.sa_mask);

		if (sigaction(sig->signo, &sa, NULL) == -1) 
		{
			return -1;
		}
	}

	_init = true;

	return 0;
}

void Signal::handler(int signo)
{
	Signal::signal_t * sig;

	for (sig = _signals; sig->signo != 0; ++ sig)
	{
		if (signo == sig->signo)
		{
			break;
		}
	}

	switch (signo)
	{
		case SIG_RELOAD:
			{
				_op  = OP_RELOAD;
			}
			break;

		case SIG_STOP:
			{
				_op  = OP_STOP;
			}
			break;

		default :
			{
				std::cout << "Error: unknown signal. signo: " << signo << std::endl;
			}
			break;
	}
}

int Signal::signal_process(const std::string & pid_file, const std::string & name)
{
	if (!_init && init(pid_file) < 0)
	{
		std::cout << "signal init failed." << std::endl;
		return -1;
	}

	pid_t pid   = get_pid();

	Signal::signal_t * sig;

	for (sig = _signals; sig->signo != 0; ++ sig)
	{
		if (strcmp(name.c_str(), sig->name) == 0) 
		{
			if (kill(pid, sig->signo) != -1) 
			{
				return 0;
			}

			std::cout << "kill(" << _pid << ", " << sig->signo << ") failed" << std::endl;
		}
	}

	return -1;
}

pid_t Signal::get_pid()
{
	std::ifstream fin;
	pid_t    pid;
	
	fin.open(_pid_file.c_str(), std::ios::in);
	fin >> pid;
	fin.close();

	return pid;
}

void Signal::log_pid()
{
	_pid = getpid();

	std::ofstream fout;

	fout.open(_pid_file.c_str(), std::ios::trunc);
	fout << _pid;
	fout.close();
}

